package com.iwhalecloud.citybrain.flow.platform.manager.application.service.impl;

import com.alibaba.algo.cooperation.common.BaseResult;
import com.alibaba.algo.cooperation.feign.service.RoleFeignService;
import com.alibaba.algo.cooperation.feign.vo.req.SelectRoleUserReqVO;
import com.alibaba.algo.cooperation.feign.vo.res.RoleUserInfoResVO;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.iwhalecloud.citybrain.flow.platform.manager.application.service.ProcessInstanceStartPostProcessor;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.task.FlowUserTaskRoleInfoVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.FlowUserTaskRoleInfoRepository;
import org.apache.commons.lang3.StringUtils;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.UserTask;
import org.flowable.engine.DynamicBpmnService;
import org.flowable.engine.ManagementService;
import org.flowable.engine.ProcessEngineConfiguration;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.common.impl.interceptor.Command;
import org.flowable.engine.common.impl.interceptor.CommandContext;
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.impl.util.ProcessDefinitionUtil;
import org.flowable.engine.repository.ProcessDefinition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * @author: niechanggang
 * @date:2021/8/19 22:12
 * @description:  处理任务节点有角色选择的情况
 */
@Order(10)
@Component
public class UserTaskRoleProcessor  implements ProcessInstanceStartPostProcessor {

    private Logger  logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private ManagementService managementService;


    @Autowired
    private FlowUserTaskRoleInfoRepository flowUserTaskRoleInfoRepository;

    @Autowired
    private RoleFeignService roleFeignService;

    @Autowired
    private DynamicBpmnService dynamicBpmnService;


    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private ProcessEngineConfigurationImpl processEngineConfiguration;

    @Override
    public void process(ExecutionEntity executionEntity) {
        final  String processDefinitionId = executionEntity.getProcessDefinitionId();
        managementService.executeCommand(new Command<Void>() {
            public  Void execute(CommandContext commandContext){
                String  deployId = repositoryService.createProcessDefinitionQuery().processDefinitionId(processDefinitionId).singleResult().getDeploymentId();
                Process process = ProcessDefinitionUtil.getProcess(processDefinitionId);
                Collection<FlowElement> flowElements = process.getFlowElements();
                boolean flag = false;
                for(FlowElement flowElement : flowElements){
                    if(flowElement instanceof  UserTask){
                        UserTask userTask = (UserTask)flowElement;
                        if(!userTask.hasMultiInstanceLoopCharacteristics()){
                            flag = true;
                            break;
                        }
                    }
                }
                if(flag == false){
                    return null;
                }
                ObjectNode infoNode = processEngineConfiguration.getObjectMapper().createObjectNode();
                for(FlowElement flowElement : flowElements){
                    if(flowElement instanceof UserTask){
                        UserTask userTask = (UserTask)flowElement;
                        if(userTask.hasMultiInstanceLoopCharacteristics()){
                            //多实例任务
                            continue;
                        }
                        String nodeCode = userTask.getId();
                        FlowUserTaskRoleInfoVo flowUserTaskRoleInfoVo = flowUserTaskRoleInfoRepository.selectByDeployIdAndNodeCode(deployId, nodeCode);
                        if(flowUserTaskRoleInfoVo != null){
                            String  candidateUsersStr = flowUserTaskRoleInfoVo.getCandidateUsers();
                            String  roleIdsStr =  flowUserTaskRoleInfoVo.getRoleIds();
                            if(StringUtils.isNotEmpty(roleIdsStr)){
                                Set<String> candidateUsers = new HashSet<>();
                                if(StringUtils.isNotEmpty(candidateUsersStr)){
                                    String[] candidateUserArr =  candidateUsersStr.split(",");
                                    for(String candidateUser : candidateUserArr){
                                        candidateUsers.add(candidateUser);
                                    }
                                }
                                String[] roleIdArr = roleIdsStr.split(",");
                                for(String roleId : roleIdArr){
                                    SelectRoleUserReqVO selectRoleUserReqVO = new  SelectRoleUserReqVO();
                                    selectRoleUserReqVO.setRoleId(Long.parseLong(roleId));
                                    BaseResult<List<RoleUserInfoResVO>> result = roleFeignService.qryUserListByRoleId(selectRoleUserReqVO);
                                    List<RoleUserInfoResVO> dataList = result.getData();
                                    if(dataList != null){
                                        for(RoleUserInfoResVO  roleUserInfoResVO : dataList){
                                            candidateUsers.add(roleUserInfoResVO.getUserId()+"");
                                        }
                                    }
                                }
                                List<String> candidateUserList = new ArrayList<>(candidateUsers);
                                dynamicBpmnService.changeUserTaskCandidateUsers(nodeCode, new ArrayList<>(candidateUserList), infoNode);

                                logger.info("DefId:"+processDefinitionId+" CandidateUsers:"+candidateUserList.size());
                            }
                        }
                    }
                }
                dynamicBpmnService.saveProcessDefinitionInfo(processDefinitionId, infoNode);
                return null;
            }
        });
    }
}
